// async implement async/await wrapper
package async

import (
	"context"
)

type Future[T any] interface {
	Await() T
}

type future[T any] struct {
	await func(ctx context.Context) T
}

func (f future[T]) Await() T {
	return f.await(context.Background())
}

// Exec invoke a function asynchronously
//
// Question: how to implement an "await Task<void>"?
func Exec[T1 any, T2 FunctionReturnSingleValue[T1]](f interface{}, args ...interface{}) Future[T1] {
	var value T1
	ch := make(chan struct{})
	go func() {
		defer close(ch)
		value = invokeReturnSingleValue[T1](f, args...)
	}()
	return future[T1]{
		await: func(ctx context.Context) T1 {
			select {
			case <-ctx.Done():
				panic(ctx.Err())
			case <-ch:
				return value
			}
		},
	}
}
